#ifndef _FLY_OBJECT_
#define _FLY_OBJECT_

#include "aerial\Game\GameObject\GameObject.h"
#include "aerial\Game\GameObject\Equipment\VulcanEquip.h"

#include "aerial\Game\GameScene\BattleScene.h"

#include "aerial\Game\Helper\BattleHelper.h"

#include "hge\hge.h"
#include "hge\hgeresource.h"

#include "raknet\BitStream.h"
#include "Box2D\Box2D.h"

using namespace air;
using namespace RakNet;

class Shield;
class Propeller;

class Weapon;

class BattleScene;

#define M_SHIELD	0x1
#define M_ACCEL		0x2

class FlyObject: public GameObject
{
	friend class Shield;
public:
	static void SetInputEvent(hgeInputEvent*);
	static void SetBattleScene(BattleScene*);

	FlyObject::FlyObject(float x, float y, float A, int _id, const char* usrname, uchar side);
	virtual ~FlyObject();
	virtual bool FlyObject::update(float dt);

	virtual uchar GetFlightType() = 0;

	virtual void DeSerializationFull(BitStream* p);
	virtual void DeSerializationIncrement(BitStream* p);

	virtual void SerializationFull(BitStream*);
	virtual void SerializationIncrement(BitStream*);

	inline bool IsAvailable() { return !toDestroy; }

	/// @brief status[l..r] = status
	inline void SetState(ushort n_status, ushort d_mask)
	{
		if (n_status == (status & d_mask)) d_status &= (~d_mask); 
		else 
		{
			d_status |= d_mask;
			status &= (~d_mask); status |= n_status;
		}
	}

	inline virtual uchar GetObjectType() {	return TYPE_FLY; }
	inline float GetPower() const { return power; }
	inline float GetArmor() const { return armor; }
	inline ushort GetStateChange() const { return d_status; }
	inline void SetArmor(float _armor) { armor = _armor; if (armor <= 0.f) Die();	}
	inline void SetStateChange(ushort _d_status) { d_status = _d_status; }
	inline virtual bool IsStateChange() { if (d_status) return true; return false; }
	inline bool UsePower(float amount) 
	{ 
		power -= amount;
		if (power <= 0) {
			power = 0;
			return true;
		}
		else return false;
	}

	/// @brief define flyobject' s reaction to a weapon
	void TakeEffect(Weapon*);
	/// @brief define flyobject' s reaction to a flyobject
	void TakeEffect(FlyObject* fObj);
	/// @brief define flyobject' s reaction to a vulcan
	void TakeEffect(VulcanEquip* vulcan);

	void UpdateArmor();

	/// @brief control shield
	void HandleShield();
	/**
	 * @brief react according to input
	 *
	 * @param ievnt record event
	 */
	virtual void processInput() = 0;
	void Die() 
	{
		GameObject::Die();
		status = 0; 
		d_status = 0; 
		toDestroy = true; 
		if (side) --battleScene->alivePlayerCount[1];
		else --battleScene->alivePlayerCount[0];
	}
	void SetMeSide(uchar _side) { MeSide = _side; }

	uchar side;
	uchar MeSide;
protected:
	/// @brief record current status of flyobject
	ushort status;
	/// @brief record whether current status has been push to the server
	ushort d_status;
	/// @brief armor for a flyobject
	float armor;
	/// @brief power for a flyobject
	float power;
	/// @brief username to be shown beside the flyobject
	const char* username;
	/// @brief shield for a flyobject
	Shield* shield;
	/// @brief propeller for a flyobject
	Propeller* propeller;
	/// @brief record the mouse's last horizontal position
	float lastX;
	/// @brief record the mouse's last vertical position
	float lastY;


	static hgeInputEvent* inputEvent;
	static BattleScene* battleScene;
};

#endif
